/*
 * mainTask.c
 *
 *  Created on: Jun 9, 2021
 *      Author: soliber
 */

#include "main.h"
#include "usart.h"
#include "i2c.h"
#include "adc.h"
#include "cmsis_os2.h"
#include "mainTask.h"
#include "Modbus.h"
#include "bmp280.h"
#include "ssd1306.h"
#include "semphr.h"

//固件版本
#define FW_VERSION (0x0001)

/*
 * modbus实例
 */
static modbusHandler_t hmodbus1;	//实例（第三方库）
static struct modbus_registers_map modregs;	//寄存器表

/*
 * 主任务事件信号
 */
#define EVENT_VOLT_ALARM	(1UL<<0)
#define EVENT_PRES_ALARM	(1UL<<1)
osEventFlagsId_t EventsHandle;
const osEventFlagsAttr_t Events_attributes = {
  .name = "Events"
};

/*
 * 电压测量
 */
/* Definitions for VoltAcqTimer */
osTimerId_t VoltAcqTimerHandle;
const osTimerAttr_t VoltAcqTimer_attributes = {
  .name = "VoltAcqTimer"
};
/* Definitions for VoltFIFO */
osMessageQueueId_t VoltFIFOHandle;
const osMessageQueueAttr_t VoltFIFO_attributes = {
  .name = "VoltFIFO"
};
void VoltAcq(void * argument);

/*
 * 气压测量
 */
struct bmp280_comp_data
{
	uint32_t pres;
	uint32_t temp;
};
static struct bmp280_dev bmp280;
/* Definitions for PresAcqTimer */
osTimerId_t PresAcqTimerHandle;
const osTimerAttr_t PresAcqTimer_attributes = {
  .name = "PresAcqTimer"
};
/* Definitions for PresFIFO */
osMessageQueueId_t PresFIFOHandle;
const osMessageQueueAttr_t PresFIFO_attributes = {
  .name = "PresFIFO"
};
void PresAcq(void * argument);
static void delay_ms(uint32_t period_ms);
static int8_t i2c_reg_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data,uint16_t length);
static int8_t i2c_reg_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data,uint16_t length);

/*
 * FLASH配置
 */
void FLASH_LoadConfig(struct modbus_registers_map * config);
void FLASH_SaveConfig(struct modbus_registers_map * config);

/*
 * 报警指示灯
 */
/* Definitions for AlarmTimer */
osTimerId_t AlarmTimerHandle;
const osTimerAttr_t AlarmTimer_attributes = {
  .name = "AlarmTimer"
};
#define SAFE_ON()		HAL_GPIO_WritePin(SAFE_GPIO_Port,SAFE_Pin,SET)
#define SAFE_OFF()		HAL_GPIO_WritePin(SAFE_GPIO_Port,SAFE_Pin,RESET)
#define RESCUE_ON()		HAL_GPIO_WritePin(RESCUE_GPIO_Port,RESCUE_Pin,SET)
#define RESCUE_OFF()	HAL_GPIO_WritePin(RESCUE_GPIO_Port,RESCUE_Pin,RESET)
//闪烁
void AlarmBlink(void * argument)
{
	HAL_GPIO_TogglePin(HAT_LIGHT_GPIO_Port, HAT_LIGHT_Pin);
}
void AlarmBlinkFast(void)
{
	osTimerStart(AlarmTimerHandle, 500);
}
void AlarmBlinkSlow(void)
{
	osTimerStart(AlarmTimerHandle, 1000);
}
void AlarmOn(void)
{
	osTimerStop(AlarmTimerHandle);
	HAL_GPIO_WritePin(HAT_LIGHT_GPIO_Port,HAT_LIGHT_Pin,SET);
}
void AlarmOff(void)
{
	osTimerStop(AlarmTimerHandle);
	HAL_GPIO_WritePin(HAT_LIGHT_GPIO_Port,HAT_LIGHT_Pin,RESET);
}

/*
 * 寄存器更新检查
 */
/* Definitions for regUpdateTask */
osThreadId_t regUpdateTaskHandle;
const osThreadAttr_t regUpdateTask_attributes = {
  .name = "regUpdateTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityHigh,
};
void regUpdate(void * argument);

/*
 * 状态切换
 */
void switchSAFE(void)
{
	//状态改变
	modregs.dev_stat.pre_status = modregs.dev_stat.cur_status;
	modregs.dev_stat.cur_status = modregs.dev_stat.nex_status = SAFE;
	SAFE_ON();
	RESCUE_OFF();
	//报警灯熄灭
	AlarmOff();
}
void switchALARM(void)
{
	//状态改变
	modregs.dev_stat.pre_status = modregs.dev_stat.cur_status;
	modregs.dev_stat.cur_status = modregs.dev_stat.nex_status = ALARM;
	SAFE_ON();
	RESCUE_OFF();
	//报警灯快闪
	AlarmBlinkFast();

}
void switchLOST(void)
{
	//状态改变
	modregs.dev_stat.pre_status = modregs.dev_stat.cur_status;
	modregs.dev_stat.cur_status = modregs.dev_stat.nex_status = LOST;
	SAFE_ON();
	RESCUE_OFF();
	//报警灯慢闪
	AlarmBlinkSlow();

}
void switchRESCUE(void)
{

	//关闭调度器
	//osKernelSuspend();

	//状态改变
	modregs.dev_stat.pre_status = modregs.dev_stat.cur_status;
	modregs.dev_stat.cur_status = modregs.dev_stat.nex_status = RESCUE;
	SAFE_OFF();
	RESCUE_ON();

	//报警灯常量
	AlarmOn();
	while(1);

}



/*
 * @name    StartMainTask
 * @brief   主任务
 * @detail  处理各类事件、参数修改及状态切换
 * @param   无
 * @retval  无返回值
 * @see     无
 * @note    无
 */
void StartMainTask(void const * argument)
{
	/*
	 * 从FLASH加载默认配置
	 */
	FLASH_LoadConfig(&modregs);

	/*
	 * 创建事件信号
	 */
	EventsHandle = osEventFlagsNew(&Events_attributes);
	/* creation of AlarmTimer */
	AlarmTimerHandle = osTimerNew(AlarmBlink, osTimerPeriodic, NULL, &AlarmTimer_attributes);

	/*
	 * 启动电压测量
	 */
	/* creation of VoltAcqTimer */
	VoltAcqTimerHandle = osTimerNew(VoltAcq, osTimerOnce, NULL, &VoltAcqTimer_attributes);
	/* creation of VoltFIFO */
	VoltFIFOHandle = osMessageQueueNew (16, sizeof(struct volt_rslt_regs), &VoltFIFO_attributes);
	//启动
	HAL_ADC_Start(&hadc1);
	osTimerStart(VoltAcqTimerHandle, modregs.volt_conf.period_ms);

	/*
	 * 启动气压测量
	 */
	//初始化BMP280实例
	bmp280.delay_ms = delay_ms;				//接口函数指针：延时
	bmp280.read = i2c_reg_read;				//接口函数指针：读寄存器
	bmp280.write = i2c_reg_write;			//接口函数指针：写寄存器
	bmp280.dev_id = BMP280_I2C_ADDR_PRIM;	//地址选择
	bmp280.intf = BMP280_I2C_INTF;			//接口选择：I2C
	if (BMP280_OK != bmp280_init(&bmp280)) {
		Error_Handler();
	}
	//初始化BMP280配置参数
	struct bmp280_config conf;
	if (BMP280_OK != bmp280_get_config(&conf, &bmp280)) {
		Error_Handler();
	}
	conf.filter = BMP280_FILTER_COEFF_2;
	conf.os_pres = BMP280_OS_4X;
	conf.os_temp = BMP280_OS_4X;
	conf.odr = BMP280_ODR_1000_MS;
	if (BMP280_OK != bmp280_set_config(&conf, &bmp280)) {
		Error_Handler();
	}
	if (BMP280_OK != bmp280_set_power_mode(BMP280_NORMAL_MODE, &bmp280)) {
		Error_Handler();
	}
	//初始化完成后立即触发测量一次，读取数据无用，丢弃
	struct bmp280_uncomp_data ucomp_data;
	bmp280_get_uncomp_data(&ucomp_data, &bmp280);
	/* creation of PresAcqTimer */
	PresAcqTimerHandle = osTimerNew(PresAcq, osTimerOnce, NULL, &PresAcqTimer_attributes);
	/* creation of PresFIFO */
	PresFIFOHandle = osMessageQueueNew (16, sizeof(struct pres_rslt_regs), &PresFIFO_attributes);
	//启动
	osTimerStart(PresAcqTimerHandle, modregs.pres_conf.period_ms);


	/*
	 * TODO 启动UWB测距线程
	 */


	/*
	 * 启动Modbus线程
	 */
	hmodbus1.uiModbusType = SLAVE_RTU;	//从机，RTU模式
	hmodbus1.port = &huart1;			//使用串口1
	hmodbus1.u8id = 1;					//从机地址
	hmodbus1.u16timeOut = 1000;
	hmodbus1.EN_Port = NULL;			//不使用485流控
	hmodbus1.u32overTime = 0;
	hmodbus1.au16regs = (uint16_t *)&modregs;	//modbus寄存器基址映射
	hmodbus1.u16regsize = sizeof(modregs);		//modbus寄存器大小
	ModbusInit(&hmodbus1);				//初始化实例
	ModbusStart(&hmodbus1);				//创建并开始进程

	/*
	 * 启动寄存器更新
	 */
	regUpdateTaskHandle = osThreadNew(regUpdate, NULL, &regUpdateTask_attributes);


	//进入安全模式
	switchSAFE();

	while(1)
	{
		/*
		 * 等待事件发生
		 */
		uint32_t event = osEventFlagsWait(EventsHandle,
				EVENT_PRES_ALARM,
				osFlagsWaitAny,
				osWaitForever);

		/*
		 * 处理事件
		 */
		//电压报警事件
		if(event&EVENT_VOLT_ALARM)
		{
#ifdef DEBUG
			//OLED显示
			char buf[20];
			static uint16_t alarm_cnt=0;
			alarm_cnt++;
			ssd1306_SetCursor(0, 0);
			snprintf(buf,20,"Valm cnt %d",alarm_cnt);
			ssd1306_WriteString(buf, Font_6x8, White);
			ssd1306_UpdateScreen();
#endif
		}
		//气压报警事件
		if(event&EVENT_PRES_ALARM)
		{
#ifdef DEBUG
			//OLED显示
			char buf[20];
			static uint16_t alarm_cnt=0;
			alarm_cnt++;
			ssd1306_SetCursor(0, 16);
			snprintf(buf,20,"Palm cnt %d",alarm_cnt);
			ssd1306_WriteString(buf, Font_6x8, White);
			ssd1306_UpdateScreen();
#endif
		}
		osDelay(1000);
	}
};


/*
 * @name    FLASH_LoadConfig
 * @brief   从FLASH中加载配置
 * @detail
 * @param   config 加载到的modbus寄存器基址
 * @retval  无
 * @see     无
 * @note	无
 */
void FLASH_LoadConfig(struct modbus_registers_map * config)
{
	//TODO 暂时写死，后续需要从FLASH读取
	struct dev_info_regs 	dev_info={FW_VERSION,0x0000,HELMET,0};
	struct volt_conf_regs 	volt_conf={100,10,11000,0};
	struct pres_conf_regs 	pres_conf={1000,1,100000,0};
	struct range_conf_regs 	range_conf={1000,0,0};

	//写入寄存器
	modregs.dev_info = dev_info;
	modregs.volt_conf = volt_conf;
	modregs.pres_conf = pres_conf;
	modregs.range_conf = range_conf;

}

/*
 * @name    VoltAcq
 * @brief   电压采集定时器回调
 * @detail	按照一定时间间隔采集电压
 * 			采集结果将存入FIFO
 * 			FIFO长度达到滤波点数后进行均值滤波，并将结果直接写入modbus寄存器
 * 			超出阈值将触发EVENT_VOLT_ALARM事件
 * @param   无
 * @retval  无
 * @see     无
 * @note	无
 */
void VoltAcq(void * argument)
{
	//查询转换完成
	if(HAL_ADC_PollForConversion(&hadc1, 0)!=HAL_OK)
	{
		while(1);	//错误，未在指定时间内完成转换
	}
	//停止转换
	HAL_ADC_Stop(&hadc1);
	//获取转换值
	struct volt_rslt_regs rslt;
	rslt.cur_mV = 4*HAL_ADC_GetValue(&hadc1);
	//入队
	osMessageQueuePut(VoltFIFOHandle, &rslt, 0, 0);
	//启动转换
	HAL_ADC_Start(&hadc1);

	//采集到了足够多的点数
	if(osMessageQueueGetCount(VoltFIFOHandle)>=modregs.volt_conf.filter_N)
	{
		uint8_t n = osMessageQueueGetCount(VoltFIFOHandle);
		uint32_t avg_mv = 0;
		//计算均值
		for(uint8_t i=0;i<n;i++)
		{
			struct volt_rslt_regs tmp;
			osMessageQueueGet(VoltFIFOHandle, &tmp, 0, 0);
			avg_mv += tmp.cur_mV;
		}
		avg_mv /= n;

		//放入寄存器
		modregs.volt_rslt.cur_mV = avg_mv;

		//小于阈值
		if(avg_mv < modregs.volt_conf.min_mV)
		{
			//触发报警事件
			osEventFlagsSet(EventsHandle, EVENT_VOLT_ALARM);
		}
#ifdef DEBUG
		//OLED显示
		char buf[20];

		ssd1306_SetCursor(0, 8);
		snprintf(buf,20,"volt %d mV",modregs.volt_rslt.cur_mV);
		ssd1306_WriteString(buf, Font_6x8, White);

		ssd1306_UpdateScreen();
#endif
	}

	//再次定时
	osTimerStart(VoltAcqTimerHandle, modregs.volt_conf.period_ms);

}

/*
 * @name    PresAcq
 * @brief   气压采集定时器回调
 * @detail	按照一定时间间隔采集气压和温度
 * 			采集结果将存入FIFO
 * 			FIFO长度达到滤波点数后进行均值滤波，并将结果直接写入modbus寄存器
 * 			超出阈值将触发EVENT_PRES_ALARM事件
 * @param   无
 * @retval  无
 * @see     无
 * @note	无
 */
void PresAcq(void * argument)
{
	struct bmp280_uncomp_data ucomp_data;
	//读传感器原始数据并开始新的转换
	bmp280_get_uncomp_data(&ucomp_data, &bmp280);

	//计算气压和温度修正值
	struct pres_rslt_regs rslt;;
	bmp280_get_comp_pres_32bit(&rslt.cur_Pa, ucomp_data.uncomp_press, &bmp280);
	bmp280_get_comp_temp_32bit(&rslt.cur_10mC, ucomp_data.uncomp_temp, &bmp280);

	//入队
	osMessageQueuePut(PresFIFOHandle, &rslt, 0, 0);

	//采集到了足够多的点数
	if(osMessageQueueGetCount(PresFIFOHandle)>=modregs.pres_conf.filter_N)
	{
		uint8_t n = osMessageQueueGetCount(PresFIFOHandle);
		uint64_t avg_Pa=0,avg_10mC=0;
		//计算均值
		for(int i = 0; i<n;i++)
		{
			struct pres_rslt_regs tmp;
			osMessageQueueGet(PresFIFOHandle, &tmp, 0, 0);
			avg_Pa += tmp.cur_Pa;
			avg_10mC += tmp.cur_10mC;
		}
		avg_Pa /= n;
		avg_10mC /= n;

		//放入寄存器
		modregs.pres_rslt.cur_Pa = avg_Pa;
		modregs.pres_rslt.cur_10mC = avg_10mC;

		//超出阈值
		if(avg_Pa > modregs.pres_conf.max_Pa)
		{
			//触发报警事件
			osEventFlagsSet(EventsHandle, EVENT_PRES_ALARM);
			//气压过高导致的状态切换
			if(modregs.dev_stat.cur_status==SAFE)
			{
				switchALARM();
			}
		}
#ifdef DEBUG
		//OLED显示
		char buf[20];

		ssd1306_SetCursor(0, 24);
		snprintf(buf,20,"pres %ld Pa",modregs.pres_rslt.cur_Pa);
		ssd1306_WriteString(buf, Font_6x8, White);

		ssd1306_SetCursor(0, 32);
		snprintf(buf,20,"temp %ld 0.01C",modregs.pres_rslt.cur_10mC);
		ssd1306_WriteString(buf, Font_6x8, White);

		ssd1306_UpdateScreen();
#endif
	}

	//再次定时
	osTimerStart(PresAcqTimerHandle, modregs.pres_conf.period_ms);

}

/**
 * BMP280接口移植
 */

//延时
static void delay_ms(uint32_t period_ms)
{
	osDelay(period_ms);
}
//写寄存器
static int8_t i2c_reg_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data,uint16_t length)
{
	if (HAL_OK == HAL_I2C_Mem_Write(&hi2c1, i2c_addr << 1, reg_addr,
	I2C_MEMADD_SIZE_8BIT, reg_data, length, HAL_MAX_DELAY))
		return 0;
	else
		return -1;
}
//读寄存器
static int8_t i2c_reg_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data,uint16_t length)
{
	if (HAL_OK == HAL_I2C_Mem_Read(&hi2c1, i2c_addr << 1, reg_addr,
	I2C_MEMADD_SIZE_8BIT, reg_data, length, HAL_MAX_DELAY))
		return 0;
	else
		return -1;
}

//寄存器更新处理进程
void regUpdate(void * argument)
{
	while(1)
	{
		//等待信号量
		//TODO 信号量为什么不阻塞？
		osStatus_t st = osSemaphoreAcquire(hmodbus1.ModBusSphrHandle, 1000);
		if(st ==osOK)
		{
#ifdef DEBUG
			HAL_GPIO_TogglePin(EVAL_LED2_GPIO_Port, EVAL_LED2_Pin);
#endif
			//如果需要，进行状态切换
			if(modregs.dev_stat.nex_status!=modregs.dev_stat.cur_status)
			{
				switch(modregs.dev_stat.nex_status)
				{
				case SAFE:
					switchSAFE();
					break;
				case ALARM:
					switchALARM();
					break;
				case RESCUE:
					switchRESCUE();
					break;
				case LOST:
					switchLOST();
					break;
				}
			}
			// TODO 失联处理

			osSemaphoreRelease(hmodbus1.ModBusSphrHandle);
		}

		osDelay(1000);
	}

}
